﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsistentHashing
{
    public class ConsistentHashing
    {
        //一个物理节点对应的虚拟节点个数
        private int virtualNodeNum = 320;
        //hash map，需要对key排序，形成有序hash环
        private SortedList<int, string> hashNodes = new SortedList<int, string>();
        //物理节点名称列表
        List<string> nodeNames = new List<string>();
        //物理节点操作主体列表
        List<Node> nodes = new List<Node>();
        //物理节点和节点名称的对应列表
        Dictionary<string, Node> nodeDic = new Dictionary<string, Node>();
        //物理节点对用的配置
        Dictionary<string, string> nodeConfigDic = new Dictionary<string, string>();

        public ConsistentHashing(List<string> nodeNames)
        {
            this.nodeNames = nodeNames;
            InitNodesHash();
        }

        public void SetNodeConfigs(Dictionary<string, string> nodeConfigs)
        {
            this.nodeConfigDic = nodeConfigs;
        }

        public void InitNodes()
        {
            foreach(var name in nodeNames)
            {
                Node node = new Node(nodeConfigDic[name]);
                nodeDic.Add(name, node);
            }
        }

        //初始化节点
        public void InitNodesHash()
        {
            foreach (string nodeName in nodeNames)
            {
                HashVirtualNodes(nodeName);
            }
        }

        //散列虚拟节点
        private void HashVirtualNodes(string nodeName)
        {
            for (int i = 0; i < virtualNodeNum; i++)
            {
                string virNodeName = nodeName + "#VN" + i;
                int hash = HashAlgorithm(virNodeName);
                hashNodes[hash] = nodeName;
            }
        }

        //获取节点
        public string GetNodeName(int key)
        {
            var tailMap = from coll in hashNodes
                          where coll.Key > key
                          select new { coll.Key };
            if (tailMap == null || tailMap.Count() == 0)
                key = hashNodes.FirstOrDefault().Key;
            else
                key = tailMap.FirstOrDefault().Key;

            return hashNodes[key];
        }

        public Node GetNode(string nodeName)
        {
            if(nodeDic.ContainsKey(nodeName))
            {
                return nodeDic[nodeName];
            }
            return null;
        }

        public Node GetNode(int key)
        {
            var tailMap = from coll in hashNodes
                          where coll.Key > key
                          select new { coll.Key };
            if (tailMap == null || tailMap.Count() == 0)
                key = hashNodes.FirstOrDefault().Key;
            else
                key = tailMap.FirstOrDefault().Key;

            if (nodeDic.ContainsKey(hashNodes[key]))
            {
                return nodeDic[hashNodes[key]];
            }
            return null;
        }

        //增加节点
        public void AddNode(string node)
        {
            if (!hashNodes.ContainsValue(node))
            {
                //添加节点
                HashVirtualNodes(node);
            }
        }

        //移除失效节点
        public void RemoveNode(string node)
        {
            if (hashNodes.ContainsValue(node))
            {
                //移除节点
                hashNodes = (SortedList<int, string>)from col in hashNodes where col.Value != node select new { col };
            }
        }

        //哈希算法
        public static int HashAlgorithm(string value)
        {
            int p = 16777619;
            int hash = 0;
            unchecked { hash = (int)2166136261; }
            for (int i = 0; i < value.Length; i++)
                hash = (hash ^ value.ElementAt(i)) * p;
            hash += hash << 13;
            hash ^= hash >> 7;
            hash += hash << 3;
            hash ^= hash >> 17;
            hash += hash << 5;

            // 如果算出来的值为负数则取其绝对值
            if (hash < 0)
            {
                hash = Math.Abs(hash);
            }
            return hash;
        }
    }
}
